package com.hengxinyongli.iam.service;

import com.google.common.collect.Lists;
import com.hengxinyongli.iam.dto.Subject;
import com.hengxinyongli.iam.entity.*;
import com.hengxinyongli.iam.mapper.DepartmentResourceMapper;
import com.hengxinyongli.iam.mapper.ResourceMapper;
import com.hengxinyongli.iam.mapper.RoleResourceMapper;
import com.hengxinyongli.iam.mapper.UserRoleMapper;
import com.hengxinyongli.iam.utils.AssertUtils;
import com.hengxinyongli.iam.web.constant.Res;
import com.hengxinyongli.iam.web.controller.UserController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.LinkedList;
import java.util.List;
import java.util.Objects;


/**
 * @author magic
 * @date 2018/9/25/025 9:27
 * @version 1.0
 * Description ResourceService
 */
@Service
public class ResourceService {

    @Autowired
    ResourceMapper resourceMapper;
    @Autowired
    UserRoleMapper userRoleMapper;
    @Autowired
    DepartmentResourceMapper departmentResourceMapper;
    @Autowired
    RoleResourceMapper roleResourceMapper;

    public List<Resource> selectByType(String type, String pid, Subject subject) {
        List<String> params = processType(type);
        List<Resource> resources = resourceMapper.selectByType(params, pid);
        if(!Res.DEFAULT_ROOT_PARENT_ID.equals(pid) && Objects.nonNull(pid)){
            LinkedList<Resource> rootRes = new LinkedList<>(resources);
            while (!rootRes.isEmpty()){
                Resource first = rootRes.removeFirst();
                List<Resource> subRes = resourceMapper.selectByType(params, first.getId());
                if(!subRes.isEmpty()){
                    rootRes.addAll(0,subRes);
                    resources.addAll(subRes);
                }
            }
            Resource rootNode = resourceMapper.selectByPrimaryKey(pid);
            if(Objects.nonNull(rootNode)){
                resources.add(rootNode);
            }
        }
        return resources;
    }

    private List<String> processType(String type) {
        List<String> params = Lists.newArrayList();
        switch (type){
            case Res.ALL:
                params.add(Res.MENU);
                params.add(Res.BUTTON);
                break;
            case Res.MENU:
                params.add(Res.MENU);
                break;
            case Res.BUTTON:
                params.add(Res.BUTTON);
                break;
            default:
                params.add(type);
                break;
        }
        return params;
    }

    public List<Resource> selectByModelSelective(Resource resource, boolean b) {
        return resourceMapper.selectByModelSelective(resource,b);
    }

    public Resource selectById(String id) {
        return resourceMapper.selectByPrimaryKey(id);
    }

    public void resourceCreate(Resource resource) {
        Integer level = -1;
        boolean isRootNode = false;
        if(Objects.nonNull(resource.getParentId()) && !resource.getParentId().equals(Res.DEFAULT_ROOT_PARENT_ID)){
            Resource parentRes = resourceMapper.selectByPrimaryKey(resource.getParentId());
            AssertUtils.isTrue(Objects.nonNull(parentRes),"parentRes not allow be null.");
            level = parentRes.getLevel() + 1;
            isRootNode = true;
        }
        resource.setLevel(Short.parseShort(String.valueOf(level)));
        resource.setOrderSeq(Long.parseLong(String.valueOf(level)));
        String rootParentId = resource.getParentId();

        if(isRootNode){
            if(Res.ROOT_ID_LENGTH < resource.getParentId().length()){
                rootParentId = rootParentId.substring(0,4);
            }
            String id = resourceMapper.generateId(rootParentId);
            resource.setId(id);
        }else{
            String id = resourceMapper.generateId(null);
            resource.setId(id);
        }
        resourceMapper.insertSelective(resource);
    }

    @Cacheable(value = "iamRes",key="T(String).valueOf(#userId).concat(#type)")
    public List<Resource> selectUserResourcesByType(Long userId, String type) {
        List<String> types = processType(type);
        return resourceMapper.selectUserResourceByType(userId,types);
    }

    @Cacheable(value = "iamUserInfo",key="T(String).valueOf(#user.id).concat(#type)")
    public UserController.UserInfo selectUserInfoResourcesByType(User user, String type) {
        UserController.UserInfo userInfo = new UserController.UserInfo();
        userInfo.setUserBase(user);
        userInfo.setAdmin(false);
        List<Resource> resources = selectUserResourcesByType(user.getId(),type);
        List<Resource> menus = Lists.newArrayList();
        List<Resource> btns = Lists.newArrayList();
        List<String> isAdmin = Lists.newArrayList();
        List<String> roles = Lists.newArrayList();
        resources.forEach(resource -> {
            if(Res.BUTTON.equals(resource.getType())){
                btns.add(resource);
            }
            if(Res.MENU.equals(resource.getType())){
                menus.add(resource);
            }
            if(Res.ADMIN_URL_MAPPING.equalsIgnoreCase(resource.getUrl())
                    && Res.BUTTON.equalsIgnoreCase(resource.getType())){
                isAdmin.add(resource.getCode());
            }
        });
        userInfo.setMenus(menus);
        userInfo.setBtns(btns);
        if(!isAdmin.isEmpty()){
            userInfo.setAdmin(true);
        }
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        List<UserRole> userRoles = userRoleMapper.selectByModelSelective(userRole,true);
        userRoles.forEach(ur -> roles.add(ur.getRoleId()));
        userInfo.setRoles(roles);
        return userInfo;
    }

    public void resourceUpdate(String id,Resource resource) {
        Resource currentRes = resourceMapper.selectByPrimaryKey(id);
        AssertUtils.isTrue(Objects.nonNull(currentRes),"currentRes not allow be null.");
        if(StringUtils.hasLength(resource.getParentId()) && !resource.getParentId().equals(Res.DEFAULT_ROOT_PARENT_ID)){
            Resource parentRes = resourceMapper.selectByPrimaryKey(resource.getParentId());
            AssertUtils.isTrue(Objects.nonNull(parentRes),"parentRes not allow be null.");
        }
        resource.setId(id);
        resourceMapper.updateByPrimaryKeySelective(resource);
    }

    public void resourceDelete(String id) {
        Resource currentRes = resourceMapper.selectByPrimaryKey(id);
        AssertUtils.isTrue(Objects.nonNull(currentRes),"currentRes not allow be null.");
        DepartmentResource departmentResource = new DepartmentResource();
        departmentResource.setResourceId(id);
        List departmentResources = departmentResourceMapper.selectByModelSelective(departmentResource,true);
        if(!departmentResources.isEmpty()){
            departmentResourceMapper.deleteByModelSelective(departmentResource,true);
        }
        //AssertUtils.isTrue(departmentResources.isEmpty(),"当前资源绑定了部门信息,请先解除绑定关系.");
        RoleResource roleResource = new RoleResource();
        roleResource.setResourceId(id);
        List roleResources = roleResourceMapper.selectByModelSelective(roleResource,true);
        //AssertUtils.isTrue(roleResources.isEmpty(),"当前资源绑定了角色信息,请先解除绑定关系.");
        if(!roleResources.isEmpty()){
            roleResourceMapper.deleteByModelSelective(roleResource,true);
        }
        resourceMapper.deleteByPrimaryKey(id);
    }
}
